#NoTrayIcon

#Include <Array.au3>
#Include <Constants.au3>
#Include <File.au3>
#Include <Process.au3>
#Include <String.au3>

#Include <ButtonConstants.au3>
#Include <ComboConstants.au3>
#Include <EditConstants.au3>
#Include <GUIConstantsEx.au3>
#Include <GuiStatusBar.au3>
#Include <ProgressConstants.au3>
#Include <StaticConstants.au3>
#Include <WindowsConstants.au3>

; Use Skins
;#Include "_UskinLibrary.au3"
;#Include "AzenisBlack.au3"

; Load Skin
;_Uskin_LoadDLL()
;_USkin_Init( _AzenisBlack( True ))

; Special Settings
Opt( 'TrayMenuMode'    , 3 )
Opt( 'TrayOnEventMode' , 1 )

; Set HotKeys
HotKeySet( '^!{ESC}' , '_Exit' )

$Process_Flag = False

; Create Tray Menu Items And Set The Events
$Show = TrayCreateItem( 'Show' )
TrayItemSetOnEvent( $Show , '_Show' )
TrayCreateItem('') ; Create a separator line.
$Exit = TrayCreateItem( 'Exit' )
TrayItemSetOnEvent( $Exit , "_Exit" )
; Set the action if you left click on the tray icon
TraySetOnEvent( $TRAY_EVENT_PRIMARYUP , '_Show' )
; Show the menu if the icon is right clicked
TraySetClick( 8 )

Global $Complete , $FileDir , $FileExt , $FileName , $FinalExt , $Parent , $ShortName
Global $String_AVI_File , $String_AVI_Post , $String_MKV_File , $String_MKV_Post , $String_MP4_File
Global $ErrorLog , $TempFolder , $GUIFinalExt
Global $Initial_Time
Global $Size_Old = 0 , $Size_New = 0

Dim $Extensions= '*.3gp;*.avi;*.avs;*.divx;*.f4v;*.flv;*.m4v;*.mkv;*.mp4;*.mpg;*.ogm;*.vob'

Dim $Quality_V = '00|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|50'
Dim $Preset		= 'UltraFast|SuperFast|VeryFast|Faster|Fast|Medium|Slow|Slower|VerySlow|Placebo'
Dim $Tuning		= 'Animation|FastDecode|Film|Grain|PSNR|SSIM|StillImage|ZeroLatency'
; FHGaacEnc
;Dim $Quality_A= '01|02|03|04|05|06'
; Qaac
Dim $Quality_A = '06|12|18|24|30|36|42|48|54|60|66|72|78|84|90|96|102|108|114|120|126'


; Create Basic Settings If Required
If NOT FileExists( @ScriptDir & '\Settings.ini' ) Then _BasicSettings()

; Read Settings INI Values
$INI_Encode		= IniRead( @ScriptDir & '\Settings.ini' , 'H264' , 'Encode' , 'False' )
$INI_Preset		= IniRead( @ScriptDir & '\Settings.ini' , 'H264' , 'Preset' , 'Medium' )
$INI_Tuning		= IniRead( @ScriptDir & '\Settings.ini' , 'H264' , 'Tuning' , 'Film' )
$INI_Quality_V	= IniRead( @ScriptDir & '\Settings.ini' , 'H264' , 'Quality', '23' )

$INI_MKV			= IniRead( @ScriptDir & '\Settings.ini' , 'Force' , 'MKV'		, 'True' )
$INI_MP4			= IniRead( @ScriptDir & '\Settings.ini' , 'Force' , 'MP4'		, 'False' )
$INI_Replace	= IniRead( @ScriptDir & '\Settings.ini' , 'Force' , 'Replace'	, 'False' )

$INI_Deinterlace = IniRead( @ScriptDir & '\Settings.ini' , 'Deinterlace' , 'Value' , 'False' )

$INI_Encoder	= IniRead( @ScriptDir & '\Settings.ini' , 'Encoder' , 'Value' , 'x264 8bit' )

$INI_AC3			= IniRead( @ScriptDir & '\Settings.ini' , 'Preserve' , 'AC3' , 'False' )
$INI_DTS			= IniRead( @ScriptDir & '\Settings.ini' , 'Preserve' , 'DTS' , 'False' )

$INI_Quality_A	= IniRead( @ScriptDir & '\Settings.ini' , 'Settings' , 'Quality' , '90' )
$INI_Recurse	= IniRead( @ScriptDir & '\Settings.ini' , 'Settings' , 'Recurse' , 'False' )
$INI_ShutDown	= IniRead( @ScriptDir & '\Settings.ini' , 'Settings' , 'Shutdown', 'False' )

$INI_Pathing	= IniRead( @ScriptDir & '\Settings.ini' , 'Last Path' , 'Path' , '' )

; Check INI vs Array's
$INI_Preset		= _CheckGUIArray( $INI_Preset		, $Preset	, 'Medium' )
$INI_Tuning		= _CheckGUIArray( $INI_Tuning		, $Tuning	, 'Film' )
$INI_Quality_V	= _CheckGUIArray( $INI_Quality_V , $Quality_V, '23' )
;$INI_Quality_A= _CheckGUIArray( $INI_Quality_A , $Quality_A, '04' ) ; FHGaacEnc
$INI_Quality_A	= _CheckGUIArray( $INI_Quality_A , $Quality_A, '90' ) ; Qaac

#Region ### START Koda GUI section ###
	$VideoGain = GUICreate("Video Gain - v1.37", 388, 288, 342, 343)

	$Force				= GUICtrlCreateGroup("Force", 8, 4, 114, 80)
	$ChkBox_MKV			= GUICtrlCreateCheckbox("MKV", 20, 23, 41, 17)
	$ChkBox_MP4			= GUICtrlCreateCheckbox("MP4", 70, 23, 41, 17)
	$ChkBox_Replace	= GUICtrlCreateCheckbox("Direct Replace", 20, 52, 97, 17)
	GUICtrlCreateGroup("", -99, -99, 1, 1)

	If $INI_MKV			= 'True' Then GUICtrlSetState( $ChkBox_MKV , $GUI_CHECKED )
	If $INI_MP4			= 'True' Then GUICtrlSetState( $ChkBox_MP4 , $GUI_CHECKED )
	If $INI_Replace	= 'True' Then GUICtrlSetState( $ChkBox_Replace , $GUI_CHECKED )

	$H264					= GUICtrlCreateGroup("H264", 132, 4, 245, 80)
	$ChkBox_Encode		= GUICtrlCreateCheckbox("Re - Encode:", 145, 23, 81, 17, BitOR($GUI_SS_DEFAULT_CHECKBOX,$BS_RIGHTBUTTON))
	$Label_Quality		= GUICtrlCreateLabel("Quality:", 144, 54, 39, 17)
	$Combo_Quality		= GUICtrlCreateCombo("", 185, 52, 41, 25, BitOR($CBS_DROPDOWNLIST,$CBS_AUTOHSCROLL))
		GUICtrlSetData ( -1 , $Quality_V , $INI_Quality_V )
	$Label_Preset		= GUICtrlCreateLabel("Preset:", 245, 25, 37, 17)
	$Combo_Preset		= GUICtrlCreateCombo("", 284, 21, 81, 25, BitOR($CBS_DROPDOWNLIST,$CBS_AUTOHSCROLL))
		GUICtrlSetData ( -1 , $Preset , $INI_Preset )
	$Label_Tuning		= GUICtrlCreateLabel("Tuning:", 242, 54, 40, 17)
	$Combo_Tuning		= GUICtrlCreateCombo("", 284, 52, 81, 25, BitOR($CBS_DROPDOWNLIST,$CBS_AUTOHSCROLL))
		GUICtrlSetData ( -1 , $Tuning , $INI_Tuning )
	GUICtrlCreateGroup("", -99, -99, 1, 1)

	If $INI_Encode		= 'True' Then GUICtrlSetState( $ChkBox_Encode , $GUI_CHECKED )

	$Deinterlace		= GUICtrlCreateGroup("Deinterlace", 8, 88, 114, 49)
	$DI_Yes				= GUICtrlCreateRadio("Yes", 20, 107, 41, 17)
	$DI_No				= GUICtrlCreateRadio("No", 70, 107, 41, 17)
	GUICtrlCreateGroup("", -99, -99, 1, 1)

	If $INI_Deinterlace = 'True'	Then GUICtrlSetState( $DI_Yes , $GUI_CHECKED )
	If $INI_Deinterlace = 'False'	Then GUICtrlSetState( $DI_No  , $GUI_CHECKED )

	$SelectEncoder		= GUICtrlCreateGroup("Encoder", 132, 88, 245, 49)
	$FFMpeg				= GUICtrlCreateRadio("FFMpeg", 144, 107, 65, 17)
	$x264_8bit			= GUICtrlCreateRadio("x264 8bit", 220, 107, 81, 17)
	$x264_10bit			= GUICtrlCreateRadio("x264 10bit", 300, 107, 65, 17)
	GUICtrlCreateGroup("", -99, -99, 1, 1)

	If $INI_Encoder	= 'FFMpeg'		Then GUICtrlSetState( $FFMpeg		, $GUI_CHECKED )
	If $INI_Encoder	= 'x264 8bit'	Then GUICtrlSetState( $x264_8bit	, $GUI_CHECKED )
	If $INI_Encoder	= 'x264 10bit'	Then GUICtrlSetState( $x264_10bit, $GUI_CHECKED )

	$Preserve			= GUICtrlCreateGroup("Preserve", 8, 141, 114, 49)
	$ChkBox_AC3			= GUICtrlCreateCheckbox("AC3", 20, 160, 49, 17)
	$ChkBox_DTS			= GUICtrlCreateCheckbox("DTS", 70, 160, 49, 17)
	GUICtrlCreateGroup("", -99, -99, 1, 1)

	If $INI_AC3			= 'True' Then GUICtrlSetState( $ChkBox_AC3 , $GUI_CHECKED )
	If $INI_DTS			= 'True' Then GUICtrlSetState( $ChkBox_DTS , $GUI_CHECKED )

	$Settings			= GUICtrlCreateGroup("Settings", 132, 141, 245, 49)
	$Label_Audio		= GUICtrlCreateLabel("Audio Quality:", 144, 162, 69, 17)
	$Combo_Audio		= GUICtrlCreateCombo("", 215, 158, 41, 25, BitOR($CBS_DROPDOWNLIST,$CBS_AUTOHSCROLL))
		GUICtrlSetData ( -1 , $Quality_A , $INI_Quality_A )
	$ChkBox_Recurse	= GUICtrlCreateCheckbox("Recurse Folders:", 260, 160, 105, 17, BitOR($GUI_SS_DEFAULT_CHECKBOX,$BS_RIGHTBUTTON,$BS_RIGHT))
	GUICtrlCreateGroup("", -99, -99, 1, 1)

	If $INI_Recurse	= 'True' Then GUICtrlSetState( $ChkBox_Recurse , $GUI_CHECKED )

	$Input_FolderPath	= GUICtrlCreateInput("", 8, 200, 347, 21)
	$Button_FolderPath= GUICtrlCreateButton("...", 355, 199, 23, 23)

	If FileExists( $INI_Pathing ) Then GUICtrlSetData( $Input_FolderPath , $INI_Pathing )

	$Process				= GUICtrlCreateGroup("", 8, 225, 369, 51)
	$ChkBox_Shutdown	= GUICtrlCreateCheckbox("Shutdown when finished.", 20, 245, 145, 17)
	$Button_Exit		= GUICtrlCreateButton("Exit", 211, 241, 75, 25)
	$Button_Run			= GUICtrlCreateButton("Run", 291, 241, 75, 25)
	GUICtrlCreateGroup("", -99, -99, 1, 1)

	If $INI_ShutDown	= 'True' Then GUICtrlSetState( $ChkBox_Shutdown , $GUI_CHECKED )

	GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

#Region ### START Koda GUI section ###
;	$Progress = GUICreate("Video Gain - Progress", 413, 260, 365, 601 , -1 , -1 , $VideoGain )
	$Progress = GUICreate("Video Gain - Progress", 413, 260, 365, 601 )

	$Progress_Group_1 = GUICtrlCreateGroup(" Over All ", 8, 8, 393, 57)
	$Progress_1			= GUICtrlCreateProgress(16, 32, 374, 17)
	GUICtrlCreateGroup("", -99, -99, 1, 1)

	$Progress_Group_2 = GUICtrlCreateGroup(" Current File ", 8, 77, 393, 57)
	$Progress_2			= GUICtrlCreateProgress(16, 101, 374, 17)
	GUICtrlCreateGroup("", -99, -99, 1, 1)

	$Progress_Group_3 = GUICtrlCreateGroup(" Current Stream ", 8, 144, 393, 57)
	$Progress_3			= GUICtrlCreateProgress(16, 168, 374, 17)
	GUICtrlCreateGroup("", -99, -99, 1, 1)

	$Label_Process    = GUICtrlCreateLabel("Processing :", 8, 212, 62, 17)
	$Label_Processing = GUICtrlCreateLabel("", 72, 212, 244, 17)

	$Progress_Exit		= GUICtrlCreateButton("&Exit", 326, 208, 75, 25)
	$Progress_StatusBar = _GUICtrlStatusBar_Create($Progress)
	_GUICtrlStatusBar_SetText($Progress_StatusBar, "")
	GUISetState(@SW_HIDE)
#EndRegion ### END Koda GUI section ###

While 1
	$Msg = GUIGetMsg()
	Switch $Msg
		Case $GUI_EVENT_CLOSE
			_WriteSettings()
			Exit
		Case $Button_Exit
			_WriteSettings()
			Exit
		Case $GUI_EVENT_MINIMIZE
			If $Process_Flag Then
				$Show_String = $Progress 
			Else
				$Show_String = $VideoGain 
			EndIf
			; Hide the GUI
			GUISetState( @SW_HIDE , $Show_String )
			; Show the icon
			TraySetState(1)
		Case $ChkBox_MKV
			_Toggle_CheckBox( $ChkBox_MKV , $ChkBox_MP4 )
		Case $ChkBox_MP4
			_Toggle_CheckBox( $ChkBox_MP4 , $ChkBox_MKV )
		Case $Button_FolderPath
			$CurrentPath = GUICtrlRead( $Input_FolderPath )
			If NOT FileExists( $CurrentPath ) Then
				$CurrentPath = ''
			EndIf
			$Folder = FileSelectFolder( 'Select Video Folder.' , '' , 2 , $CurrentPath )
			If NOT @Error Then
				If StringRight( $Folder , 1 ) <> '\' Then $Folder &= '\'
				GUICtrlSetData( $Input_FolderPath , $Folder )
			EndIf
		Case $Button_Run
			$Videos  = GUICtrlRead( $Input_FolderPath )
			$Quality = '0.' & GUICtrlRead( $Combo_Audio )
			$AC3 = GUICtrlRead( $ChkBox_AC3 )
			$DTS = GUICtrlRead( $ChkBox_DTS )
			$EFR = GUICtrlRead( $ChkBox_Recurse )
			$Shutdown = GUICtrlRead( $ChkBox_Shutdown )
			If $EFR = 1 Then
				$EFR = True
			Else
				$EFR = False
			EndIf
			$Replace  = GUICtrlRead( $ChkBox_Replace )
			If $Replace = 1 Then
				$Replace = True
			Else
				$Replace = False
			EndIf
			$ReEncode = GUICtrlRead( $ChkBox_Encode )
			If $ReEncode = 1 Then
				$ReEncode = True
			Else
				$ReEncode = False
			EndIf
			$Delace  = GUICtrlRead( $DI_Yes )
			If $Delace = 1 Then
				$Delace = True
			Else
				$Delace = False
			EndIf
			If GUICtrlRead( $FFMpeg		) = 1 Then $Encoder = 'FFMpeg'
			If GUICtrlRead( $x264_8bit	) = 1 Then $Encoder = 'x264 8bit'
			If GUICtrlRead( $x264_10bit) = 1 Then $Encoder = 'x264 10bit'
			$CRF     = GUICtrlRead ( $Combo_Quality )
			$Preset  = GUICtrlRead ( $Combo_Preset )
			$Tuning  = GUICtrlRead ( $Combo_Tuning )
			$FinalExt = ''
			If BitAND( GUICtrlRead( $ChkBox_MKV ) , $GUI_CHECKED ) = $GUI_CHECKED Then $GUIFinalExt = '.mkv'
			If BitAND( GUICtrlRead( $ChkBox_MP4 ) , $GUI_CHECKED ) = $GUI_CHECKED Then $GUIFinalExt = '.mp4'
			If FileExists( $Videos ) Then
				If StringRight( $Videos , 1 ) <> '\' Then $Videos &= '\'
				Global $AllFiles = _FileListToArrayXT( $Videos , $Extensions , 1 , 2 , $EFR , '' , 1 )
				If IsArray( $AllFiles ) <> 1 Then
					MsgBox( 4096 , 'Error:' , 'No Video Files Found!' )
				Else
					_WriteSettings()
					AdlibRegister( '_Progress_Exit' , 100 )
;					TraySetState( 1 )
					GUISetState( @SW_HIDE , $VideoGain )
					GUISetState( @SW_SHOW , $Progress )
					$Process_Flag = True
					_Main()
					$Process_Flag = False
					GUISetState( @SW_HIDE , $Progress )
					GUISetState( @SW_SHOW , $VideoGain )
;					TraySetState( 2 )
					AdlibUnRegister( '_Progress_Exit' )
				EndIf
				Global $AllFiles
			Else
				MsgBox( 4096 , 'Error:' , 'Invalid Path given.' )
			EndIf
	EndSwitch
WEnd

;   //////////////////////////////////////////////////////////////////////////////////////////////////////////////
;  // Main Function
; //////////////////////////////////////////////////////////////////////////////////////////////////////////////

Func _Main()
	; Create Temp Folder
	$TempFolder = @TempDir & '\Video Gain\'
	If NOT FileExists( $TempFolder ) Then DirCreate ( $TempFolder )

	; Start Timer
	$Initial_Time = TimerInit()

	; Counters
	Global $Count_Files  = $AllFiles[0]
	$Count_Errors = 0

	For $i = 1 To $AllFiles[0]
		; Test If File Still Exists
		If NOT FileExists( $AllFiles[$i] ) Then
			$Count_Files -= 1
			ContinueLoop
		EndIf

		; Remove Junk
		FileDelete ( $TempFolder )
		$TempFiles = _FileListToArrayXT( $TempFolder , '*.*' , 1 , 2 , False , '' , 1 )
		If IsArray( $TempFiles ) Then
			For $j = 1 To $TempFiles[0]
				RunWait( @ComSpec & ' /c Unlocker.exe "' & $TempFiles[$j] & '" /S /D' , @ScriptDir & '\BIN\Unlocker\' , @SW_HIDE )
			Next
		EndIf

		; Clear Strings
		$String_AVI_File = ''
		$String_AVI_Post = ''
		$String_MKV_File = ''
		$String_MKV_Post = ''
		$String_MP4_File = ''

		; Define Macro's
		$FileDir		= StringLeft	 	( $AllFiles[$i] , StringInStr ( $AllFiles[$i] , '\' , 0 , -1 ) )
		$FileExt		= StringTrimLeft	( $AllFiles[$i] , StringInStr ( $AllFiles[$i] , '.' , 0 , -1 ) - 1 )
		$FileName	= StringTrimLeft	( $AllFiles[$i] , StringInStr ( $AllFiles[$i] , '\' , 0 , -1 ) )
		$ShortName	= StringLeft		( $FileName		 , StringInStr ( $FileName		 , '.' , 0 , -1 ) - 1 )
		$Parent		= StringTrimLeft	( $FileDir		 , StringInStr ( $FileDir		 , '\' , 0 , -2 ) )
		$Complete	= $FileDir & 'Complete\'
		$FinalExt	= $FileExt

		; Test Final Video Container #1
		If $FinalExt = '.avs' Then $FinalExt = '.mkv'

		; Test Final Video Container #2
		If $GUIFinalExt <> '' Then $FinalExt = $GUIFinalExt

		; Skip if in Complete Folder
		If $Replace = False AND StringInStr( $AllFiles[$i] , 'Complete\' ) <> 0 Then ContinueLoop

		; Skip if Already Completed
		If $Replace = False AND FileExists ( $Complete & $ShortName & '.*' ) Then ContinueLoop

		; Update Progress Processing Label
		GUICtrlSetData( $Label_Processing , $ShortName )

		; Display TrayTip
		If BitAND( WinGetState( $Progress ) , 2 ) <> 2 Then TrayTip ( '' , 'Processing #' & $i & ' of ' & $AllFiles[0] & @LF & 'Video: ' & $ShortName , 10 , 16 )

		; Change Progress Title
		WinSetTitle( $Progress , '' , 'Video Gain - Progress (' & $i & ' of ' & $AllFiles[0] & ')' )

		; Grab Stream Output
		$Output = ''
		$Read = Run( @ComSpec & ' /c ffprobe.exe -show_streams "' & $AllFiles[$i] & '"' , @ScriptDir & '\BIN\FFMpeg\' , @SW_HIDE , $STDOUT_CHILD )
		While 1
			$Output &= StdoutRead( $Read )
			If @Error Then ExitLoop
		WEnd

		; Global File Count
		Global $File_Count = $i - 1

		; Build Array of Streams
		Global $Streams_All = _StringBetween( $Output , '[STREAM]' , '[/STREAM]' )

		; Set Active File Count
		Dim $Active_File_Count[1] = [0]

		; Build Active File Array
		$File_Array = ''

		; Create Stream Count
		Global $Stream_Count = 0

		; Create Stream Count for All Streams
		Global $Streams_Count_All = UBound( $Streams_All ) + 2

		; Define Count & Content For Video Streams
		$Streams_Find = _ArrayFindAll( $Streams_All , 'codec_type=video' , 0 , 0 , 0 , 1 )
		If $Streams_Find = -1 Then
			Dim $Streams_Video[1] = [0]
		Else
			Dim $Streams_Video[1] = [UBound ( $Streams_Find )]
			For $a = 0 To UBound( $Streams_Find ) - 1
				_ArrayAdd( $Streams_Video , $Streams_All[$Streams_Find[$a]] )
			Next
			; Build Array Based on FFProbe Info
			For $a = 1 To $Streams_Video[0]
				Global $Array_Video[15][2]=[[' 0 Index'								] , _
													[ ' 1 Codec Name'							] , _
													[ ' 2 Width'								] , _
													[ ' 3 Height'								] , _
													[ ' 4 Sample Aspect Ratio'				] , _
													[ ' 5 Display Aspect Ratio'			] , _
													[ ' 6 Pixel Format'						] , _
													[ ' 7 Render Frame Rate Numerator'	] , _
													[ ' 8 Render Frame Rate Denominator'] , _
													[ ' 9 Language'							] , _
													[ '10 Start Time'							] , _
													[ '11 Duration'							] , _
													[ '12 Lang Meta'							] , _
													[ '13 Name Meta'							] , _
													[ '14 Number of Frames'					] ]

				$Find_String = StringSplit (	'(?i)(?s).+index=(\S+)|'						& _
														'(?i)(?s).+codec_name=(\S+)|'					& _
														'(?i)(?s).+width=(\S+)|'						& _
														'(?i)(?s).+height=(\S+)|'						& _
														'(?i)(?s).+sample_aspect_ratio=(\S+)|'		& _
														'(?i)(?s).+display_aspect_ratio=(\S+)|'	& _
														'(?i)(?s).+pix_fmt=(\S+)|'						& _
														'(?i)(?s).+r_frame_rate=(\d+)/|'				& _
														'(?i)(?s).+r_frame_rate=\d+/(\d+)|'			& _
														'(?i)(?s).+language=(\S+)|'					& _
														'(?i)(?s).+start_time=(\S+)|'					& _
														'(?i)(?s).+duration=(\S+)|'					& _
														'(?i)(?s).+TAG:language=(\S+)|'				& _
														'(?i)(?s).+TAG:title=(\V+)|'					& _
														'(?i)(?s).+nb_frames=(\S+)'					  _
														, '|' )

				; Add Secondary Values to Array
				For $b = 1 To $Find_String[0]
					$Found = StringRegExp ( $Streams_Video[$a] , $Find_String[$b] , 1 )
					If @Error Then Dim $Found[1]=['N/A']
					$Array_Video[$b - 1][1] = _ArrayToString( $Found )
				Next
;				_ArrayDisplay( $Array_Video )

				; Double Index Count
				If StringLen( $a ) = 1 Then $Double_Count = '0' & $a
				If StringLen( $a ) = 2 Then $Double_Count = $a

				; Set AVI Meta
				$AVI_Meta = ''
				If $Array_Video[9][1]  <> 'N/A' Then $AVI_Meta &= ' -vlang "'             & $Array_Video[9][1]	& '"'
				If $Array_Video[12][1] <> 'N/A' Then $AVI_Meta &= ' -metadata language="' & $Array_Video[12][1]	& '"'
				If $Array_Video[12][1] <> 'N/A' Then $AVI_Meta &= ' -metadata title="'    & $Array_Video[13][1]	& '"'

				; Set MKV Meta
				$MKV_Meta = ''
				If $Array_Video[9][1]  <> 'N/A' Then $MKV_Meta &= ' --language 0:"'   & $Array_Video[9][1]	& '"'
				If $Array_Video[13][1] <> 'N/A' Then $MKV_Meta &= ' --track-name 0:"' & $Array_Video[13][1]	& '"'

				; Set MP4 Meta
				$MP4_Meta = ''
				If $Array_Video[9][1]  <> 'N/A' Then $MP4_Meta &= ':lang="' & $Array_Video[9][1]	& '"'
				If $Array_Video[13][1] <> 'N/A' Then $MP4_Meta &= ':name="' & $Array_Video[13][1]	& '"'

				; Deinterlace
				$Deinterlace = ''
				If $FileExt = '.vob' Then $Deinterlace = ' -deinterlace'
				If $Delace  = True	Then $Deinterlace = ' -deinterlace'

				; Update Current Stream Progress
				GUICtrlSetData( $Progress_3 , 0 )

				; Decide to Re-Encode or Not
				If $Array_Video[1][1] <> 'h264' AND $ReEncode = True Then
					Switch $Encoder
						Case 'x264 8bit'
							$Stream_PID = Run( @ComSpec & ' /c .\FFMpeg\ffmpeg.exe -i "' & $AllFiles[$i] & '" -map 0:' & $Array_Video[0][1] & ' -c rawvideo -f rawvideo' & $Deinterlace & ' - | .\x264\x264-8bit.exe --tune ' & $Tuning & ' --crf ' & $CRF & ' --preset ' & $Preset & ' --fps ' & $Array_Video[7][1] / $Array_Video[8][1] & ' --input-res ' & $Array_Video[2][1] & 'x' & $Array_Video[3][1] & ' --output "' & $TempFolder & 'Video_' & $Double_Count & '.mp4" -' , @ScriptDir & '\BIN\' , @SW_HIDE , $STDERR_CHILD + $STDOUT_CHILD )
						Case 'x264 10bit'
							$Stream_PID = Run( @ComSpec & ' /c .\FFMpeg\ffmpeg.exe -i "' & $AllFiles[$i] & '" -map 0:' & $Array_Video[0][1] & ' -c rawvideo -f rawvideo' & $Deinterlace & ' - | .\x264\x264-10bit.exe --tune ' & $Tuning & ' --crf ' & $CRF & ' --preset ' & $Preset & ' --fps ' & $Array_Video[7][1] / $Array_Video[8][1] & ' --input-res ' & $Array_Video[2][1] & 'x' & $Array_Video[3][1] & ' --output "' & $TempFolder & 'Video_' & $Double_Count & '.mp4" -' , @ScriptDir & '\BIN\' , @SW_HIDE , $STDERR_CHILD + $STDOUT_CHILD )
						Case Else
							$Stream_PID = Run( @ComSpec & ' /c ffmpeg.exe -i "' & $AllFiles[$i] & '" -map 0:' & $Array_Video[0][1] & ' -c:v libx264 -tune ' & $Tuning & ' -crf ' & $CRF & ' -preset ' & $Preset & $Deinterlace & ' "' & $TempFolder & 'Video_' & $Double_Count & '.mp4"' , @ScriptDir & '\BIN\FFMpeg\' , @SW_HIDE , $STDERR_CHILD + $STDOUT_CHILD )
					EndSwitch
					; Test Container Extension
					If $FinalExt <> '.avi' AND $FinalExt <> '.f4v' AND $FinalExt <> '.m4v' AND $FinalExt <> '.mkv' AND $FinalExt <> '.mp4' Then $FinalExt = '.mkv'
					; Update Statusbar
					_GUICtrlStatusBar_SetText( $Progress_StatusBar , '  Encoding Video Stream ' & $a & ' of ' & $Streams_Video[0] )
				Else
					$Stream_PID = Run( @ComSpec & ' /c ffmpeg.exe -i "' & $AllFiles[$i] & '" -map 0:' & $Array_Video[0][1] & ' -c copy -y "' & $TempFolder & 'Video_' & $Double_Count & '.mp4"' , @ScriptDir & '\BIN\FFMpeg\' , @SW_HIDE , $STDERR_CHILD + $STDOUT_CHILD )
					; Update Statusbar
					_GUICtrlStatusBar_SetText( $Progress_StatusBar , '  Copying Video Stream ' & $a & ' of ' & $Streams_Video[0] )
				EndIf

				; Update Current Stream Progress
				Dim $Stream_Feed
				While 1
					$Stream_Feed = StderrRead( $Stream_PID )
					If @Error Then ExitLoop
					If StringInStr( $Stream_Feed , 'frame=' ) Then
						$Feed_Count = StringRegExp( $Stream_Feed , '(?i)frame=\h*(\H+)\h' , 3 )
						If IsArray( $Feed_Count ) Then
							$Precent_1 = ( $Feed_Count[UBound( $Feed_Count ) - 1] / $Array_Video[14][1] ) * 100
							$Precent_2 = ((( $Precent_1 / 100 ) / $Streams_Count_All ) + ( $Stream_Count / $Streams_Count_All )) * 100
							$Precent_3 = ((( $Precent_2 / 100 ) / $Count_Files ) + ( $File_Count / $Count_Files )) * 100
							GUICtrlSetData( $Progress_1 , $Precent_3 )
							GUICtrlSetData( $Progress_2 , $Precent_2 )
							GUICtrlSetData( $Progress_3 , $Precent_1 )
						EndIf
					EndIf
					Sleep( 10 )
				WEnd

				; Set Strings
				$String_AVI_File &= ' -i ' & FileGetShortName( $TempFolder & 'Video_' & $Double_Count & '.mp4' ) & $AVI_Meta
				$String_AVI_Post &= ''
				$String_MKV_File &= ' -d 0 -A -S -T' & $MKV_Meta & ' "' & $TempFolder & 'Video_' & $Double_Count & '.mp4' & '"'
				$String_MKV_Post &= ''
				$String_MP4_File &= ' -add ' & FileGetShortName( $TempFolder & 'Video_' & $Double_Count & '.mp4' ) & ':fps=' & $Array_Video[7][1] / $Array_Video[8][1] & $MP4_Meta

				; Increase Active File Count
				$Active_File_Count[0] += 1

				; Add File to File Count
				_ArrayAdd( $Active_File_Count , 'Video_' & $Double_Count & '.mp4' )

				; Test If File Was Actually Created
				If NOT FileExists( $TempFolder & 'Video_' & $Double_Count & '.mp4' ) OR FileGetSize( $TempFolder & 'Video_' & $Double_Count & '.mp4' ) < 10240 Then
					$ErrorLog &= 'Failed to Create Video Stream ' & $Double_Count & ' For:' & @CRLF & $AllFiles[$i] & @CRLF & @CRLF
					$Count_Errors += 1
					ContinueLoop 2
				EndIf

				; Update Current File Progress
				$Stream_Count += 1
			Next
		EndIf

		; Define Count & Content For Audio Streams
		$Streams_Find = _ArrayFindAll( $Streams_All , 'codec_type=audio' , 0 , 0 , 0 , 1 )
		If $Streams_Find = -1 Then
			Dim $Streams_Audio[1] = [0]
		Else
			Dim $Streams_Audio[1] = [UBound ( $Streams_Find )]
			For $a = 0 To UBound( $Streams_Find ) - 1
				_ArrayAdd( $Streams_Audio , $Streams_All[$Streams_Find[$a]] )
			Next
			; Build Array Based on FFProbe Info
			For $a = 1 To $Streams_Audio[0]
				Global $Array_Audio[9][2]=[[ '0 Index'			] , _
													[ '1 Codec Name'	] , _
													[ '2 Sample Rate'	] , _
													[ '3 Channels'		] , _
													[ '4 Language'		] , _
													[ '5 Start Time'	] , _
													[ '6 Duration'		] , _
													[ '7 Lang Meta'	] , _
													[ '8 Name Meta'	] ]

				$Find_String = StringSplit (	'(?i)(?s).+index=(\S+)|'			& _
														'(?i)(?s).+codec_name=(\S+)|'		& _
														'(?i)(?s).+sample_rate=(\S+)|'	& _
														'(?i)(?s).+channels=(\S+)|'		& _
														'(?i)(?s).+language=(\S+)|'		& _
														'(?i)(?s).+start_time=(\S+)|'		& _
														'(?i)(?s).+duration=(\S+)|'		& _
														'(?i)(?s).+TAG:language=(\S+)|'	& _
														'(?i)(?s).+TAG:title=(\V+)'		  _
														, '|' )

				; Add Secondary Values to Array
				For $b = 1 To $Find_String[0]
					$Found = StringRegExp ( $Streams_Audio[$a] , $Find_String[$b] , 1 )
					If @Error Then Dim $Found[1]=['N/A']
					$Array_Audio[$b - 1][1] = _ArrayToString( $Found )
				Next
;				_ArrayDisplay( $Array_Audio )

				; Double Index Count
				If StringLen( $a ) = 1 Then $Double_Count = '0' & $a
				If StringLen( $a ) = 2 Then $Double_Count = $a

				; Set AVI Meta
				$AVI_Meta = ''
				If $Array_Audio[4][1] <> 'N/A' Then $AVI_Meta &= ' -alang "'             & $Array_Audio[4][1]	& '"'
				If $Array_Audio[7][1] <> 'N/A' Then $AVI_Meta &= ' -metadata language="' & $Array_Audio[7][1]	& '"'
				If $Array_Audio[8][1] <> 'N/A' Then $AVI_Meta &= ' -metadata title="'    & $Array_Audio[8][1]	& '"'

				; Set MKV Meta
				$MKV_Meta = ''
				If $Array_Audio[4][1] <> 'N/A' Then $MKV_Meta &= ' --language 0:"'   & $Array_Audio[4][1]	& '"'
				If $Array_Audio[8][1] <> 'N/A' Then $MKV_Meta &= ' --track-name 0:"' & $Array_Audio[8][1]	& '"'

				; Set Meta
				$MP4_Meta = ''
				If $Array_Audio[4][1] <> 'N/A' Then $MP4_Meta &= ':lang="' & $Array_Audio[4][1]	& '"'
				If $Array_Audio[8][1] <> 'N/A' Then $MP4_Meta &= ':name="' & $Array_Audio[8][1]	& '"'

				; Set Audio Extension
				Select
					Case $Array_Audio[1][1] = 'MP3'
						$Audio_Ext = '.mp3'
						_GUICtrlStatusBar_SetText( $Progress_StatusBar , '  Copying Audio Stream ' & $a & ' of ' & $Streams_Audio[0] )
						_Sound  ( $Double_Count , $Audio_Ext , $AllFiles[$i] , $Array_Audio[0][1] , 2 )
						_GUICtrlStatusBar_SetText( $Progress_StatusBar , '  Normalize Audio Stream ' & $a & ' of ' & $Streams_Audio[0] )
						_AACGain( $Double_Count , $Audio_Ext )
						$Index_A = 0
					Case $Array_Audio[1][1] = 'AAC'
						$Audio_Ext = '.mp4'
						_GUICtrlStatusBar_SetText( $Progress_StatusBar , '  Copying Audio Stream ' & $a & ' of ' & $Streams_Audio[0] )
						_Sound  ( $Double_Count , $Audio_Ext , $AllFiles[$i] , $Array_Audio[0][1] , 2 )
						_GUICtrlStatusBar_SetText( $Progress_StatusBar , '  Normalize Audio Stream ' & $a & ' of ' & $Streams_Audio[0] )
						_AACGain( $Double_Count , $Audio_Ext )
						$Index_A = 1
					Case $Array_Audio[1][1] = 'AC3' AND $AC3 = 1
						$Audio_Ext = '.ac3'
						_GUICtrlStatusBar_SetText( $Progress_StatusBar , '  Copying Audio Stream ' & $a & ' of ' & $Streams_Audio[0] )
						_Sound  ( $Double_Count , $Audio_Ext , $AllFiles[$i] , $Array_Audio[0][1] , 1 )
						$Index_A = 0
					Case $Array_Audio[1][1] = 'DCA' AND $DTS = 1
						$Audio_Ext = '.dts'
						_GUICtrlStatusBar_SetText( $Progress_StatusBar , '  Copying Audio Stream ' & $a & ' of ' & $Streams_Audio[0] )
						_Sound  ( $Double_Count , $Audio_Ext , $AllFiles[$i] , $Array_Audio[0][1] , 1 )
						$Index_A = 0
					Case Else
						$Audio_Ext = '.mp4'
						_GUICtrlStatusBar_SetText( $Progress_StatusBar , '  Encoding Audio Stream ' & $a & ' of ' & $Streams_Audio[0] )
						_Convert( $Double_Count , $Audio_Ext , $AllFiles[$i] , $Array_Audio[0][1] )
						_GUICtrlStatusBar_SetText( $Progress_StatusBar , '  Normalize Audio Stream ' & $a & ' of ' & $Streams_Audio[0] )
						_AACGain( $Double_Count , $Audio_Ext )
						$Index_A = 1
				EndSelect

				; Test Audio Extension VS. Container Extension
				If $Audio_Ext = '.mp4' AND $Streams_Video[0] > 0 AND $FinalExt <> '.f4v' AND $FinalExt <> '.m4v' AND $FinalExt <> '.mkv' AND $FinalExt <> '.mp4' Then $FinalExt = '.mkv'
				If $Audio_Ext = '.mp4' AND $Streams_Video[0] = 0 AND $FinalExt <> '.f4v' AND $FinalExt <> '.m4a' AND $FinalExt <> '.mkv' AND $FinalExt <> '.mp4' Then $FinalExt = '.m4a'

				; Set Strings
				$String_AVI_File &= ' -i ' & FileGetShortName( $TempFolder & 'Audio_' & $Double_Count & $Audio_Ext ) & $AVI_Meta
				$String_AVI_Post &= ''
				$String_MKV_File &= ' -a 0 -D -S -T' & $MKV_Meta & ' "' & $TempFolder & 'Audio_' & $Double_Count & $Audio_Ext & '"'
				$String_MKV_Post &= ''
				$String_MP4_File &= ' -add ' & FileGetShortName( $TempFolder & 'Audio_' & $Double_Count & $Audio_Ext ) & $MP4_Meta

				; Increase Active File Count
				$Active_File_Count[0] += 1

				; Add File to File Count
				_ArrayAdd( $Active_File_Count , 'Audio_' & $Double_Count & $Audio_Ext )

				; Test If File Was Actually Created
				If NOT FileExists( $TempFolder & 'Audio_' & $Double_Count & $Audio_Ext ) OR FileGetSize( $TempFolder & 'Audio_' & $Double_Count & $Audio_Ext ) < 2048 Then
					$ErrorLog &= 'Failed to Create Audio Stream ' & $Double_Count & ' For:' & @CRLF & $AllFiles[$i] & @CRLF & @CRLF
					$Count_Errors += 1
					ContinueLoop 2
				EndIf

				; Update Current File Progress
				$Stream_Count += 1
			Next
		EndIf

		; Define Count & Content For SubTitle Streams
		$Streams_Find = _ArrayFindAll( $Streams_All , 'codec_type=subtitle' , 0 , 0 , 0 , 1 )
		If $Streams_Find = -1 Then
			Dim $Streams_Subs[1] = [0]
		Else
			Dim $Streams_Subs[1] = [UBound ( $Streams_Find )]
			For $a = 0 To UBound( $Streams_Find ) - 1
				_ArrayAdd( $Streams_Subs , $Streams_All[$Streams_Find[$a]] )
			Next
			; Build Array Based on FFProbe Info
			For $a = 1 To $Streams_Subs[0]
				Global $Array_Subs[7][2]=[	[ '0 Index'		] , _
													[ '1 Codec Name'	] , _
													[ '2 Language'		] , _
													[ '3 Start Time'	] , _
													[ '4 Duration'		] , _
													[ '5 Lang Meta'	] , _
													[ '6 Name Meta'	] ]

				$Find_String = StringSplit (	'(?i)(?s).+index=(\S+)|'			& _
														'(?i)(?s).+codec_name=(\S+)|'		& _
														'(?i)(?s).+language=(\S+)|'		& _
														'(?i)(?s).+start_time=(\S+)|'		& _
														'(?i)(?s).+duration=(\S+)|'		& _
														'(?i)(?s).+TAG:language=(\S+)|'	& _
														'(?i)(?s).+TAG:title=(\V+)'		  _
														, '|' )

				; Add Secondary Values to Array
				For $b = 1 To $Find_String[0]
					$Found = StringRegExp ( $Streams_Subs[$a] , $Find_String[$b] , 1 )
					If @Error Then Dim $Found[1]=['N/A']
					$Array_Subs[$b - 1][1] = _ArrayToString( $Found )
				Next
;				_ArrayDisplay( $Array_Subs )

				; Double Index Count
				If StringLen( $a ) = 1 Then $Double_Count = '0' & $a
				If StringLen( $a ) = 2 Then $Double_Count = $a

				; Set AVI Meta
				$AVI_Meta = ''
				If $Array_Subs[2][1] <> 'N/A' Then $AVI_Meta &= ' -slang "'             & $Array_Subs[2][1]	& '"'
				If $Array_Subs[5][1] <> 'N/A' Then $AVI_Meta &= ' -metadata language="' & $Array_Subs[5][1]	& '"'
				If $Array_Subs[6][1] <> 'N/A' Then $AVI_Meta &= ' -metadata title="'    & $Array_Subs[6][1]	& '"'

				; Set MKV Meta
				$MKV_Meta = ''
				If $Array_Subs[2][1] <> 'N/A' Then $MKV_Meta &= ' --language 0:"'   & $Array_Subs[2][1]	& '"'
				If $Array_Subs[6][1] <> 'N/A' Then $MKV_Meta &= ' --track-name 0":' & $Array_Subs[6][1]	& '"'

				; Set Meta
				$MP4_Meta = ''
				If $Array_Subs[2][1] <> 'N/A' Then $MP4_Meta &= ':lang="' & $Array_Subs[2][1]	& '"'
				If $Array_Subs[6][1] <> 'N/A' Then $MP4_Meta &= ':name="' & $Array_Subs[6][1]	& '"'

				; Handle Sub Codec's
				Select
					Case $Array_Subs[1][1] = 'ASS' OR $Array_Subs[1][1] = 'S_TEXT/SSA' OR $Array_Subs[1][1] = 'S_TEXT/ASS'
						$Sub_Ext = '.ass'
						RunWait( @ComSpec & ' /c ffmpeg.exe -i "' & $AllFiles[$i] & '" -map 0:' & $Array_Subs[0][1] & ' -c copy -y "' & $TempFolder & 'Sub_' & $Double_Count & '.ass"' , @ScriptDir & '\BIN\FFMpeg\' , @SW_HIDE )
						RunWait( @ComSpec & ' /c SubtitleWorkshop.exe "/CONVERT(' & $TempFolder & 'Sub_' & $Double_Count & '.ass/' & $TempFolder & 'Sub_' & $Double_Count & '.srt/SubRip/0/0)"' , @ScriptDir & '\BIN\Subtitle Workshop\' , @SW_HIDE )
					Case $Array_Subs[1][1] = 'SRT' OR $Array_Subs[1][1] = 'S_TEXT/UTF8'
						$Sub_Ext = '.srt'
						RunWait( @ComSpec & ' /c ffmpeg.exe -i "' & $AllFiles[$i] & '" -map 0:' & $Array_Subs[0][1] & ' -c copy -y "' & $TempFolder & 'Sub_' & $Double_Count & '.srt"' , @ScriptDir & '\BIN\FFMpeg\' , @SW_HIDE )
					Case Else
						$Sub_Ext = '.srt'
						Select
							Case $FileExt = '.mkv'
								RunWait( @ComSpec & ' /c mkvextract.exe tracks "' & $AllFiles[$i] & '" ' & $Array_Subs[0][1] + 1 & ':"' & $TempFolder & 'Sub_' & $Double_Count & '.srt"' , @ScriptDir & '\BIN\MKVToolNix\' , @SW_HIDE )
							Case $FileExt = '.mp4' OR $FileExt = '.m4v' OR $FileExt = '.f4v'
								RunWait( @ComSpec & ' /c MP4Box.exe -srt ' & $Array_Subs[0][1] + 1 & ' "' & $AllFiles[$i] & '"' , @ScriptDir & '\BIN\MMP4Box\' , @SW_HIDE )
								FileMove( $FileDir & $ShortName & '_' & $Array_Subs[0][1] + 1 & '_text.srt' , $TempFolder & 'Sub_' & $Double_Count & '.srt' , 9 )
						EndSelect
				EndSelect

				; Set Strings
				$String_AVI_File &= ' -i ' & FileGetShortName( $TempFolder & 'Sub_' & $Double_Count & $Sub_Ext ) & $AVI_Meta
				$String_AVI_Post &= ''
				$String_MKV_File &= ' -s 0 -A -D -T' & $MKV_Meta & ' "' & $TempFolder & 'Sub_' & $Double_Count & $Sub_Ext & '"'
				$String_MKV_Post &= ''
				$String_MP4_File &= ' -add ' & FileGetShortName( $TempFolder & 'Sub_' & $Double_Count & '.srt' ) & $MP4_Meta

				; Increase Active File Count
				$Active_File_Count[0] += 1

				; Add File to File Count
				_ArrayAdd( $Active_File_Count , 'Sub_' & $Double_Count & $Sub_Ext )

				; Test If File Was Actually Created
				If NOT FileExists( $TempFolder & 'Sub_' & $Double_Count & $Sub_Ext ) OR FileGetSize( $TempFolder & 'Sub_' & $Double_Count & $Sub_Ext ) < 2048 Then
					$ErrorLog &= 'Failed to Create Subtitle Stream ' & $Double_Count & ' For:' & @CRLF & $AllFiles[$i] & @CRLF & @CRLF
					$Count_Errors += 1
					ContinueLoop 2
				EndIf

				; Update Current File Progress
				$Stream_Count += 1
			Next
		EndIf

		; Process External Subtitles
		$SubExtensions = StringSplit( '*.aqt;*.asc;*.ass;*.dks;*.lrc;*.mpl;*.ovr;*.pan;*.pjs;*.psb;*.rt;*.rtf;*.s2k;*.sami;*.sbt;*.scr;*.smi;*.son;*.srt;*.ssa;*.sst;*.ssts;*.stl;*.tts;*.vkt;*.vsf;*.zeg' , ';' )
		$MySubExt = ''
		For $a = 1 To $SubExtensions[0]
			$MySubExt &= ';' & $ShortName & $SubExtensions[$a]
		Next
		$AllSubs = _FileListToArrayXT( $FileDir , StringTrimLeft( $MySubExt , 1 ) , 1 , 2 , False , '' , 1 )
		_ArraySort( $AllSubs , 0 , 1 )
		If IsArray( $AllSubs ) = 1 Then
			For $a = 1 To $AllSubs[0]
				; Set Sub Stream Count
				$SubCount = $Streams_Subs[0] + $a

				; Define Macro's
				$SubExt	= StringTrimLeft( $AllSubs[$a] , StringInStr ( $AllSubs[$a] , '.' , 0 , -1 ) - 1 )
				$SubName	= StringTrimLeft( $AllSubs[$a] , StringInStr ( $AllSubs[$a] , '\' , 0 , -1 ) )

				; Define FPS
				$SubFPS = StringReplace( $Array_Video[7][1] / $Array_Video[8][1] , '.' , ',' )

				; Double Index Count
				If StringLen( $SubCount ) = 1 Then $Double_Count = '0' & $SubCount
				If StringLen( $SubCount ) = 2 Then $Double_Count = $SubCount

				; RegEx Subtitle Name
				; filename (year) [track] {lang} <title>.ext
				$RegExSubTitle = StringRegExp( $SubName , '(?i)<(.+?)>' , 1 )
				$RegExSubLang	= StringRegExp( $SubName , '(?i)\{(.+?)\}' , 1 )

				; Set AVI Meta
				$AVI_Meta = ''
				If IsArray( $RegExSubLang )  = 1 Then $AVI_Meta &= ' -slang "'             & $RegExSubLang[0]	& '"'
				If IsArray( $RegExSubLang )  = 1 Then $AVI_Meta &= ' -metadata language="' & $RegExSubLang[0]	& '"'
				If IsArray( $RegExSubTitle ) = 1 Then $AVI_Meta &= ' -metadata title="'    & $RegExSubTitle[0]	& '"'

				; Set MKV Meta
				$MKV_Meta = ''
				If IsArray( $RegExSubLang )  = 1 Then $MKV_Meta &= ' --language 0:"'   & $RegExSubLang[0]		& '"'
				If IsArray( $RegExSubTitle ) = 1 Then $MKV_Meta &= ' --track-name 0:"' & $RegExSubTitle[0]	& '"'

				; Set Meta
				$MP4_Meta = ''
				If IsArray( $RegExSubLang )  = 1 Then $MP4_Meta &= ':lang="' & $RegExSubLang[0]	& '"'
				If IsArray( $RegExSubTitle ) = 1 Then $MP4_Meta &= ':name="' & $RegExSubTitle[0]	& '"'

				; Handle Sub Codec's
				Switch $SubExt
					Case '.ASS'
						$Sub_Ext = '.ass'
						RunWait( @ComSpec & ' /c Copy /Y "' & $AllSubs[$a] & '" "' & $TempFolder & 'Sub_' & $Double_Count & '.ass"' , '' , @SW_HIDE )
						RunWait( @ComSpec & ' /c SubtitleWorkshop.exe "/CONVERT(' & $AllSubs[$a] & '/' & $TempFolder & 'Sub_' & $Double_Count & '.srt/SubRip/' & $SubFPS & '/' & $SubFPS & ')"' , @ScriptDir & '\BIN\Subtitle Workshop\' , @SW_HIDE )
					Case '.SRT'
						$Sub_Ext = '.srt'
						RunWait( @ComSpec & ' /c Copy /Y "' & $AllSubs[$a] & '" "' & $TempFolder & 'Sub_' & $Double_Count & '.srt"' , '' , @SW_HIDE )
					Case Else
						$Sub_Ext = '.srt'
						RunWait( @ComSpec & ' /c SubtitleWorkshop.exe "/CONVERT(' & $AllSubs[$a] & '/' & $TempFolder & 'Sub_' & $Double_Count & '.srt/SubRip/' & $SubFPS & '/' & $SubFPS & ')"' , @ScriptDir & '\BIN\Subtitle Workshop\' , @SW_HIDE )
				EndSwitch

				; Set Strings
				$String_AVI_File &= ' -i ' & FileGetShortName( $TempFolder & 'Sub_' & $Double_Count & $Sub_Ext ) & $AVI_Meta
				$String_AVI_Post &= ''
				$String_MKV_File &= ' -s 0 -A -D -T' & $MKV_Meta & ' "' & $TempFolder & 'Sub_' & $Double_Count & $Sub_Ext & '"'
				$String_MKV_Post &= ''
				$String_MP4_File &= ' -add ' & FileGetShortName( $TempFolder & 'Sub_' & $Double_Count & '.srt' ) & $MP4_Meta

				; Test Container Extension
				If $FinalExt <> '.mkv' AND $FinalExt <> '.mp4' Then $FinalExt = '.mkv'

				; Increase Active File Count
				$Active_File_Count[0] += 1

				; Add File to File Count
				_ArrayAdd( $Active_File_Count , 'Sub_' & $Double_Count & $Sub_Ext )

				; Test If File Was Actually Created
				If NOT FileExists( $TempFolder & 'Sub_' & $Double_Count & $Sub_Ext ) OR FileGetSize( $TempFolder & 'Sub_' & $Double_Count & $Sub_Ext ) < 2048 Then
					$ErrorLog &= 'Failed to Create External Subtitle Stream ' & $Double_Count & ' For:' & @CRLF & $AllFiles[$i] & @CRLF & @CRLF
					$Count_Errors += 1
					ContinueLoop 2
				EndIf
			Next
		EndIf

		; Merge Files
		_GUICtrlStatusBar_SetText( $Progress_StatusBar , '  Merging Streams' )
		Switch $FinalExt
			Case '.mp4'
				$Stream_PID = Run( @ComSpec & ' /c mp4box.exe' & $String_MP4_File & ' -new "' & $TempFolder & $ShortName & $FinalExt & '"' , @ScriptDir & '\BIN\MP4Box\' , @SW_HIDE , $STDERR_CHILD + $STDOUT_CHILD )
				StringReplace( $String_MP4_File , ' -add ' , ' -add ' , 0 , 1 )
				Dim $Stream_Part_All = @Extended + 1
				Dim $Stream_Part
				Dim $Stream_Feed
				Dim $Stream_Percent = 100 / $Stream_Part_All
				; Update Current Stream Progress
				Dim $Stream_Feed
				While 1
					$Stream_Feed = StdoutRead( $Stream_PID )
					If @Error Then ExitLoop
					StringReplace( $Stream_Feed , ' import ' , ' foo ' , 0 , 1 )
					$Stream_Part += @Extended
					If StringInStr( $Stream_Feed , 'Importing' ) Then
						$Feed_Percent = StringRegExp( $Stream_Feed , '(?i)\((\d+)/100\)' , 3 )
						If IsArray( $Feed_Percent ) Then
							$Precent_1 = ( $Feed_Percent[UBound($Feed_Percent) - 1] / $Stream_Part_All ) + ( $Stream_Percent * ( $Stream_Part - 1 ))
							$Precent_2 = ((( $Precent_1 / 100 ) / $Streams_Count_All ) + ( $Stream_Count / $Streams_Count_All )) * 100
							$Precent_3 = ((( $Precent_2 / 100 ) / $Count_Files ) + ( $File_Count / $Count_Files )) * 100
							GUICtrlSetData( $Progress_1 , $Precent_3 )
							GUICtrlSetData( $Progress_2 , $Precent_2 )
							GUICtrlSetData( $Progress_3 , $Precent_1 )
						EndIf
					EndIf
					If StringInStr( $Stream_Feed , 'Writing' ) Then
						$Feed_Percent = StringRegExp( $Stream_Feed , '(?i)\((\d+)/100\)' , 3 )
						If IsArray( $Feed_Percent ) Then
							$Precent_1 = ( $Feed_Percent[UBound($Feed_Percent) - 1] / $Stream_Part_All ) + ( $Stream_Percent * ( $Stream_Part - 0 ))
							$Precent_2 = ((( $Precent_1 / 100 ) / $Streams_Count_All ) + ( $Stream_Count / $Streams_Count_All )) * 100
							$Precent_3 = ((( $Precent_2 / 100 ) / $Count_Files ) + ( $File_Count / $Count_Files )) * 100
							GUICtrlSetData( $Progress_1 , $Precent_3 )
							GUICtrlSetData( $Progress_2 , $Precent_2 )
							GUICtrlSetData( $Progress_3 , $Precent_1 )
						EndIf
					EndIf
					Sleep( 10 )
				WEnd
			Case '.mkv'
				$Stream_PID = Run( @ComSpec & ' /c mkvmerge.exe -o "' & $TempFolder & $ShortName & $FinalExt & '"' & $String_MKV_File , @ScriptDir & '\BIN\MKVToolNix\' , @SW_HIDE , $STDERR_CHILD + $STDOUT_CHILD )
				; Update Current Stream Progress
				Dim $Stream_Feed
				While 1
					$Stream_Feed = StdoutRead( $Stream_PID )
					If @Error Then ExitLoop
					If StringInStr( $Stream_Feed , 'Progress:' ) Then
						$Feed_Percent = StringRegExp( $Stream_Feed , '(?i)Progress\:\h*(\d+)%' , 3 )
						If IsArray( $Feed_Percent ) Then
							$Precent_1 = $Feed_Percent[UBound($Feed_Percent) - 1]
							$Precent_2 = ((( $Precent_1 / 100 ) / $Streams_Count_All ) + ( $Stream_Count / $Streams_Count_All )) * 100
							$Precent_3 = ((( $Precent_2 / 100 ) / $Count_Files ) + ( $File_Count / $Count_Files )) * 100
							GUICtrlSetData( $Progress_1 , $Precent_3 )
							GUICtrlSetData( $Progress_2 , $Precent_2 )
							GUICtrlSetData( $Progress_3 , $Precent_1 )
						EndIf
					EndIf
					Sleep( 10 )
				WEnd
			Case Else
				$Stream_PID = Run( @ComSpec & ' /c ffmpeg.exe' & $String_AVI_File & ' -c copy -y "' & $TempFolder & $ShortName & $FinalExt & '"' & $String_AVI_Post , @ScriptDir & '\BIN\FFMpeg\' , @SW_HIDE , $STDERR_CHILD + $STDOUT_CHILD )
				; Update Current Stream Progress
				Dim $Stream_Feed
				While 1
					$Stream_Feed = StderrRead( $Stream_PID )
					If @Error Then ExitLoop
					If StringInStr( $Stream_Feed , 'frame=' ) Then
						$Feed_Count = StringRegExp( $Stream_Feed , '(?i)frame=\h*(\H+)\h' , 3 )
						If IsArray( $Feed_Count ) Then
							$Precent_1 = ( $Feed_Count[UBound( $Feed_Count ) - 1] / $Array_Video[14][1] ) * 100
							$Precent_2 = ((( $Precent_1 / 100 ) / $Streams_Count_All ) + ( $Stream_Count / $Streams_Count_All )) * 100
							$Precent_3 = ((( $Precent_2 / 100 ) / $Count_Files ) + ( $File_Count / $Count_Files )) * 100
							GUICtrlSetData( $Progress_1 , $Precent_3 )
							GUICtrlSetData( $Progress_2 , $Precent_2 )
							GUICtrlSetData( $Progress_3 , $Precent_1 )
						EndIf
					EndIf
					Sleep( 10 )
				WEnd
		EndSwitch

		; Update Current File Progress
		$Stream_Count += 1

		; Total Sub Files
		$SubFileSize = 0
		For $c = 1 To $Active_File_Count[0]
			$SubFileSize += FileGetSize( $TempFolder & $Active_File_Count[$c] )
		Next
		$SubFileSize = $SubFileSize * 0.97

		; Get Size
		$Size_Temp = FileGetSize( $AllFiles[$i] )

		; Replace Orignal
		If FileExists( $TempFolder & $ShortName & $FinalExt ) AND FileGetSize( $TempFolder & $ShortName & $FinalExt ) > $SubFileSize Then
			If $Replace = True Then
				$Size_Old += $Size_Temp
				FileSetAttrib( $AllFiles[$i] , '-RA' )
				FileDelete( $AllFiles[$i] )
				_GUICtrlStatusBar_SetText( $Progress_StatusBar , '  Moving Media' )
				_MyFileCopy( $TempFolder & $ShortName & $FinalExt , $FileDir  & $ShortName & $FinalExt , 2048 )
				$Size_New += FileGetSize( $FileDir  & $ShortName & $FinalExt )
				; Delete External Subtitles
				If IsArray( $AllSubs ) Then
					For $c = 1 To $AllSubs[0]
						$Size_Old += FileGetSize( $AllSubs[$c] )
						FileSetAttrib( $AllSubs[$c] , '-RA' )
						FileDelete( $AllSubs[$c] )
					Next
				EndIf
			Else
				$Size_Old += $Size_Temp
				_GUICtrlStatusBar_SetText( $Progress_StatusBar , '  Moving Media' )
				_MyFileCopy( $TempFolder & $ShortName & $FinalExt , $Complete & $ShortName & $FinalExt , 2048 )
				$Size_New += FileGetSize( $Complete & $ShortName & $FinalExt )
			EndIf
		Else
			$ErrorLog &= 'Failed to Create Finalized Video For:' & @CRLF & $AllFiles[$i] & @CRLF & @CRLF
			$Count_Errors += 1
		EndIf

		; Update Current File Progress
		$Stream_Count += 1
	Next

	; Clear ToolTip
	TrayTip ( '' , '' , 0 , 16 )

	; Remove Temp Folder
	DirRemove( $TempFolder , 1 )

	; Create Error Log
	_ErrorLog()

	; Option Turn Off
	If $Shutdown = 1 Then
		Shutdown( 4 + 1 )
	EndIf

	; Formated File Size Diff
	$Size_Total = $Size_Old - $Size_New
	$Size_GB		= Int( $Size_Total / 1073741824 )
	$Size_MB		= Int( Mod( $Size_Total , 1073741824 ) / 1048576 )
	$Size_KB		= Int( Mod( Mod( $Size_Total , 1073741824 ) , 1048576 ) / 1024 )

	; Formated Lapsed Time.
	$Total_Time = TimerDiff( $Initial_Time )
	$Hours		= Int( $Total_Time / 3600000 )
	$Minutes		= Int( Mod( $Total_Time , 3600000 ) / 60000 )
	$Seconds		= Int( Mod( Mod( $Total_Time , 3600000 ) , 60000 ) / 1000 )

	; Finished String
	$Finished_String = $Count_Files & ' File(s) Processed in -' & @LF
	If $Hours   > 0 Then $Finished_String &= $Hours   & ' Hours '
	If $Minutes > 0 Then $Finished_String &= $Minutes & ' Minutes '
	If $Seconds > 0 Then $Finished_String &= $Seconds & ' Seconds '

	If $Size_Total > 0 Then $Finished_String &= @LF & @LF & 'Total File Savings -' & @LF
	If $Size_GB	   > 0 Then $Finished_String &= $Size_GB & ' GB '
	If $Size_MB	   > 0 Then $Finished_String &= $Size_MB & ' MB '
	If $Size_KB	   > 0 Then $Finished_String &= $Size_KB & ' KB '

	MsgBox( 0 , 'Finished' , $Finished_String & @LF & @LF & 'Total Errors: ' & $Count_Errors )
EndFunc

;   //////////////////////////////////////////////////////////////////////////////////////////////////////////////
;  // Sub Functions
; //////////////////////////////////////////////////////////////////////////////////////////////////////////////
Func _Progress_Exit()
	$Msg = GUIGetMsg()
	If $Msg = $Progress_Exit Then _Exit()
	If $Msg = $GUI_Event_Minimize Then
		If $Process_Flag Then
			$Show_String = $Progress 
		Else
			$Show_String = $VideoGain 
		EndIf
		; Hide the GUI
		GUISetState( @SW_HIDE , $Show_String )
		; Show the icon
		TraySetState(1)
	EndIf
EndFunc

Func _Show()
	If $Process_Flag Then
		$Show_String = $Progress 
	Else
		$Show_String = $VideoGain 
	EndIf
	GUISetState( @SW_SHOW    , $Show_String )
	GUISetState( @SW_RESTORE , $Show_String )
	; Hide the icon
	TraySetState(2)
EndFunc

Func _Exit()
	; Close Running Processes
	$Processes = StringSplit( 'cmd.exe|aacgain.exe|ffmpeg.exe|ffprobe.exe|mkvextract.exe|mkvinfo.exe|mkvmerge.exe|mkvpropedit.exe|mp4box.exe|neroAacEnc.exe|sox.exe|SubtitleWorkshop.exe|WaveGain.exe|x264.exe|x264-8bit.exe|x264-10bit.exe' , '|' )
	For $j = 1 To $Processes[0]
		If ProcessExists( $Processes[$j] ) <> 0 Then ProcessClose( $Processes[$j] )
	Next

	_ErrorLog()

	; Formated File Size Diff
	$Size_Total = $Size_Old - $Size_New
	$Size_GB		= Int( $Size_Total / 1073741824 )
	$Size_MB		= Int( Mod( $Size_Total , 1073741824 ) / 1048576 )
	$Size_KB		= Int( Mod( Mod( $Size_Total , 1073741824 ) , 1048576 ) / 1024 )

	; Formated Lapsed Time.
	$Total_Time = TimerDiff( $Initial_Time )
	$Hours		= Int( $Total_Time / 3600000 )
	$Minutes		= Int( Mod( $Total_Time , 3600000 ) / 60000 )
	$Seconds		= Int( Mod( Mod( $Total_Time , 3600000 ) , 60000 ) / 1000 )
;	$Display_Time= StringFormat( "%02d:%02d:%02d" , $Hours , $Minutes , $Seconds )

	; Finished String
	$Finished_String = $Count_Files & ' File(s) Processed in -' & @LF
	If $Hours   > 0 Then $Finished_String &= $Hours   & ' Hours '
	If $Minutes > 0 Then $Finished_String &= $Minutes & ' Minutes '
	If $Seconds > 0 Then $Finished_String &= $Seconds & ' Seconds '

	If $Size_Total > 0 Then $Finished_String &= @LF & @LF & 'Total File Savings -' & @LF
	If $Size_GB	   > 0 Then $Finished_String &= $Size_GB & ' GB '
	If $Size_MB	   > 0 Then $Finished_String &= $Size_MB & ' MB '
	If $Size_KB	   > 0 Then $Finished_String &= $Size_KB & ' KB '

	Exit
EndFunc

Func _ErrorLog()
	; Create Error Log
	If StringLen( $ErrorLog ) > 1 Then
		If NOT FileExists( @ScriptDir & '\Error Logs\' ) Then DirCreate ( @ScriptDir & '\Error Logs\' )
		$ErrorLogFile = @ScriptDir & '\Error Logs\[' & @YEAR & '-' & @MON & '-' & @MDAY & '] ' & @HOUR & '-' & @MIN & '.txt'
		FileWrite( $ErrorLogFile , $ErrorLog )
		Run( @ComSpec & ' /c Notepad.exe "' & $ErrorLogFile & '"' , '' , @SW_HIDE )
	EndIf
EndFunc

Func _Toggle_CheckBox( $Primary , $Secondary )
	If ControlCommand( "Video Gain" , "" , $Secondary , "IsChecked" , "" ) = 1 AND ControlCommand( "Video Gain" , "" , $Primary , "IsChecked" , "" ) = 1 Then
		ControlCommand( "Video Gain" , "" , $Secondary , "UnCheck" , "" )
	EndIf
EndFunc

Func _Convert( $Count , $Ext , $File , $Map )
	; FHGaacEnc
;	$Stream_PID = Run( @ComSpec & ' /c .\FFMpeg\ffmpeg.exe -i "' & $File  & '" -map 0:' & $Map & ' -c pcm_s16le -f wav - | .\FHGaacEnc\FHGaacEnc.exe --vbr ' & $Quality & ' --ignorelength - "' & $TempFolder & 'Audio_' & $Count & $Ext & '"' , @ScriptDir & '\BIN\' , @SW_HIDE , $STDERR_CHILD + $STDOUT_CHILD )
	; Qaac
	$Stream_PID = Run( @ComSpec & ' /c .\FFMpeg\ffmpeg.exe -i "' & $File  & '" -map 0:' & $Map & ' -c pcm_s16le -f wav - | .\Qaac\Qaac.exe -V ' & $Quality & ' -q 2 -i -o "' & $TempFolder & 'Audio_' & $Count & $Ext & '" -' , @ScriptDir & '\BIN\' , @SW_HIDE , $STDERR_CHILD + $STDOUT_CHILD )
	; Update Current Stream Progress
	Dim $Stream_Feed
	While 1
		$Stream_Feed = StderrRead( $Stream_PID )
		If @Error Then ExitLoop
		If StringInStr( $Stream_Feed , 'time=' ) Then
			$Feed_Time = StringRegExp( $Stream_Feed , '(?i)time=\h*(\H+)\h' , 3 )
			If IsArray( $Feed_Time ) Then
				$Feed_Time = StringSplit( $Feed_Time[UBound($Feed_Time) - 1] , ':' )
				$Feed_Time = (( $Feed_Time[1] * 60 ) * 60 ) + ( $Feed_Time[2] * 60 ) + $Feed_Time[3]

				$Precent_1 = (( $Feed_Time / $Array_Audio[6][1] ) * 100 ) / 2
				$Precent_2 = ((( $Precent_1 / 100 ) / $Streams_Count_All ) + ( $Stream_Count / $Streams_Count_All )) * 100
				$Precent_3 = ((( $Precent_2 / 100 ) / $Count_Files ) + ( $File_Count / $Count_Files )) * 100
				GUICtrlSetData( $Progress_1 , $Precent_3 )
				GUICtrlSetData( $Progress_2 , $Precent_2 )
				GUICtrlSetData( $Progress_3 , $Precent_1 )
			EndIf
		EndIf
		Sleep( 10 )
	WEnd
EndFunc

Func _Sound( $Count , $Ext , $File , $Map , $Divisor )
	$Stream_PID = Run(  @ComSpec & ' /c ffmpeg.exe -i "' & $File  & '" -map 0:' & $Map & ' -c copy -y "' & $TempFolder & 'Audio_' & $Count & $Ext & '"' , @ScriptDir & '\BIN\FFMpeg\' , @SW_HIDE , $STDERR_CHILD + $STDOUT_CHILD )
	; Update Current Stream Progress
	Dim $Stream_Feed
	While 1
		$Stream_Feed = StderrRead( $Stream_PID )
		If @Error Then ExitLoop
		If StringInStr( $Stream_Feed , 'time=' ) Then
			$Feed_Time = StringRegExp( $Stream_Feed , '(?i)time=\h*(\H+)\h' , 3 )
			If IsArray( $Feed_Time ) Then
				$Feed_Time = StringSplit( $Feed_Time[UBound($Feed_Time) - 1] , ':' )
				$Feed_Time = (( $Feed_Time[1] * 60 ) * 60 ) + ( $Feed_Time[2] * 60 ) + $Feed_Time[3]
				$Precent_1 = (( $Feed_Time / $Array_Audio[6][1] ) * 100 ) / $Divisor
				$Precent_2 = ((( $Precent_1 / 100 ) / $Streams_Count_All ) + ( $Stream_Count / $Streams_Count_All )) * 100
				$Precent_3 = ((( $Precent_2 / 100 ) / $Count_Files ) + ( $File_Count / $Count_Files )) * 100
				GUICtrlSetData( $Progress_1 , $Precent_3 )
				GUICtrlSetData( $Progress_2 , $Precent_2 )
				GUICtrlSetData( $Progress_3 , $Precent_1 )
			EndIf
		EndIf
		Sleep( 10 )
	WEnd
EndFunc

Func _AACGain( $Count , $Ext )
	; Get File Size to Wait Time
	; Wait per 40mb
	$SizeWait = ( FileGetSize( $TempFolder & 'Audio_' & $Count & $Ext ) / 1048576 ) / 40
	If $SizeWait < 1 Then $SizeWait = 1

	; Apply Gain to AAC - Default 89db or Lower if Clipping Present
	$Stream_PID = Run( @ComSpec & ' /c aacgain.exe /s r /r /k /f "' & $TempFolder & 'Audio_' & $Count & $Ext & '"' , @ScriptDir & '\BIN\AAC Gain\' , @SW_HIDE , $STDERR_CHILD + $STDOUT_CHILD )
	; Update Current Stream Progress
	Dim $Stream_Feed
	While 1
		$Stream_Feed = StderrRead( $Stream_PID )
		If @Error Then ExitLoop
		If StringInStr( $Stream_Feed , 'analyzed' ) Then
			$Feed_Time = StringRegExp( $Stream_Feed , '(?i)(\d+)%' , 3 )
			If IsArray( $Feed_Time ) Then
				$Precent_1 = ((( $Feed_Time[UBound($Feed_Time) - 1] / 100 ) * 100 ) / 4 ) + 50
				$Precent_2 = ((( $Precent_1 / 100 ) / $Streams_Count_All ) + ( $Stream_Count / $Streams_Count_All )) * 100
				$Precent_3 = ((( $Precent_2 / 100 ) / $Count_Files ) + ( $File_Count / $Count_Files )) * 100
				GUICtrlSetData( $Progress_1 , $Precent_3 )
				GUICtrlSetData( $Progress_2 , $Precent_2 )
				GUICtrlSetData( $Progress_3 , $Precent_1 )
			EndIf
		EndIf
		If StringInStr( $Stream_Feed , 'written' ) Then
			$Feed_Time = StringRegExp( $Stream_Feed , '(?i)(\d+)%' , 3 )
			If IsArray( $Feed_Time ) Then
				$Precent_1 = ((( $Feed_Time[UBound($Feed_Time) - 1] / 100 ) * 100 ) / 4 ) + 75
				$Precent_2 = ((( $Precent_1 / 100 ) / $Streams_Count_All ) + ( $Stream_Count / $Streams_Count_All )) * 100
				$Precent_3 = ((( $Precent_2 / 100 ) / $Count_Files ) + ( $File_Count / $Count_Files )) * 100
				GUICtrlSetData( $Progress_1 , $Precent_3 )
				GUICtrlSetData( $Progress_2 , $Precent_2 )
				GUICtrlSetData( $Progress_3 , $Precent_1 )
			EndIf
		EndIf
		Sleep( 10 )
	WEnd

	; AACGain Often Finishes Prior To File
	; Being Written Out, Causing a Lock
	; Wait 1sec per
	Sleep( Int( $SizeWait * 1500 ))
EndFunc

Func _MyFileCopy( $inSource , $inDest , $ChunkSize = 2048 )
	; Open Source File for BINARY reading
	$SourceFile = FileOpen( $inSource , 16 )
	; Open Destination File for BINARY Writing,
	; OverWriting Existing File,
	; Creating Directory Structure
	$DestinFile = FileOpen( $inDest , 26 )
	; Get the Size of the File We are Going to Copy
	$SourceSize = FileGetSize( $inSource )
	; Calculate How Many Chunks We Need to Copy
	$Chunks = $SourceSize / $ChunkSize
	; Loop From 0 to Number of Chunks
	For $i = 0 To $Chunks
		; Read the Next Chunk
		$Data = FileRead( $SourceFile , $ChunkSize )
		; Write the Next Chunk
		FileWrite( $DestinFile , $Data )
		; Update Current Stream Progress
		$Precent_1 = (( $i + 1 ) / $Chunks ) * 100
		$Precent_2 = ((( $Precent_1 / 100 ) / $Streams_Count_All ) + ( $Stream_Count / $Streams_Count_All )) * 100
		$Precent_3 = ((( $Precent_2 / 100 ) / $Count_Files ) + ( $File_Count / $Count_Files )) * 100
		GUICtrlSetData( $Progress_1 , $Precent_3 )
		GUICtrlSetData( $Progress_2 , $Precent_2 )
		GUICtrlSetData( $Progress_3 , $Precent_1 )
	Next
	; Close the Source File
	FileClose( $SourceFile )
	; Close the Destination File
	FileClose( $DestinFile )
EndFunc

Func _BasicSettings()
	$BasicSettings = ''
	$BasicSettings &= '[H264]'				& @CRLF
	$BasicSettings &= 'Encode=False'		& @CRLF
	$BasicSettings &= 'Preset=Medium'	& @CRLF
	$BasicSettings &= 'Tuning=Film'		& @CRLF
	$BasicSettings &= 'Quality=23'		& @CRLF
	$BasicSettings &= @CRLF
	$BasicSettings &= '[Force]'			& @CRLF
	$BasicSettings &= 'MKV=True'			& @CRLF
	$BasicSettings &= 'MP4=False'			& @CRLF
	$BasicSettings &= 'Replace=False'	& @CRLF
	$BasicSettings &= @CRLF
	$BasicSettings &= '[Deinterlace]'	& @CRLF
	$BasicSettings &= 'Value=False'		& @CRLF
	$BasicSettings &= @CRLF
	$BasicSettings &= '[Encoder]'			& @CRLF
	$BasicSettings &= 'Value=x264 8bit'	& @CRLF
	$BasicSettings &= @CRLF
	$BasicSettings &= '[Preserve]'		& @CRLF
	$BasicSettings &= 'AC3=False'			& @CRLF
	$BasicSettings &= 'DTS=False'			& @CRLF
	$BasicSettings &= @CRLF
	$BasicSettings &= '[Settings]'		& @CRLF
	$BasicSettings &= 'Quality=40'		& @CRLF
	$BasicSettings &= 'Recurse=False'	& @CRLF
	$BasicSettings &= 'Shutdown=False'	& @CRLF
	$BasicSettings &= @CRLF
	$BasicSettings &= '[Last Path]'		& @CRLF
	$BasicSettings &= 'Path='				& @CRLF
	FileWrite( @ScriptDir & '\Settings.ini' , $BasicSettings )
EndFunc

Func _CheckGUIArray( $MyValue , $MyArray , $MyDefault )
	$MyNewArray = StringSplit( $MyArray , '|' )
	_ArraySearch( $MyNewArray , $MyValue , 1 )
	If @Error Then
		Return $MyDefault
	Else
		Return $MyValue
	EndIf
EndFunc

Func _WriteSettings()
	If GUICtrlRead( $ChkBox_MKV ) =  1 Then $MyINIMKV = 'True'
	If GUICtrlRead( $ChkBox_MKV ) <> 1 Then $MyINIMKV = 'False'
	If GUICtrlRead( $ChkBox_MP4 ) =  1 Then $MyINIMP4 = 'True'
	If GUICtrlRead( $ChkBox_MP4 ) <> 1 Then $MyINIMP4 = 'False'
	If GUICtrlRead( $ChkBox_Replace ) =  1 Then $MyINIReplace = 'True'
	If GUICtrlRead( $ChkBox_Replace ) <> 1 Then $MyINIReplace = 'False'

	If GUICtrlRead( $ChkBox_Encode ) =  1 Then $MyINIEncode = 'True'
	If GUICtrlRead( $ChkBox_Encode ) <> 1 Then $MyINIEncode = 'False'

	If GUICtrlRead( $DI_Yes ) = 1 Then $MyINIDeinterlace = 'True'
	If GUICtrlRead( $DI_No  ) = 1 Then $MyINIDeinterlace = 'False'

	If GUICtrlRead( $FFMpeg		) = 1 Then $MyINIEncoder = 'FFMpeg'
	If GUICtrlRead( $x264_8bit	) = 1 Then $MyINIEncoder = 'x264 8bit'
	If GUICtrlRead( $x264_10bit) = 1 Then $MyINIEncoder = 'x264 10bit'

	If GUICtrlRead( $ChkBox_AC3 ) =  1 Then $MyINIAC3 = 'True'
	If GUICtrlRead( $ChkBox_AC3 ) <> 1 Then $MyINIAC3 = 'False'
	If GUICtrlRead( $ChkBox_DTS ) =  1 Then $MyINIDTS = 'True'
	If GUICtrlRead( $ChkBox_DTS ) <> 1 Then $MyINIDTS = 'False'

	If GUICtrlRead( $ChkBox_Recurse ) =  1 Then $MyINIRecurse = 'True'
	If GUICtrlRead( $ChkBox_Recurse ) <> 1 Then $MyINIRecurse = 'False'
	If GUICtrlRead( $ChkBox_Shutdown) =  1 Then $MyINIShutdown = 'True'
	If GUICtrlRead( $ChkBox_Shutdown) <> 1 Then $MyINIShutdown = 'False'

	IniWrite( @ScriptDir & '\Settings.ini' , 'Force' , 'MKV'		, $MyINIMKV )
	IniWrite( @ScriptDir & '\Settings.ini' , 'Force' , 'MP4'		, $MyINIMP4 )
	IniWrite( @ScriptDir & '\Settings.ini' , 'Force' , 'Replace', $MyINIReplace )

	IniWrite( @ScriptDir & '\Settings.ini' , 'H264' , 'Encode' , $MyINIEncode )
	IniWrite( @ScriptDir & '\Settings.ini' , 'H264' , 'Preset' , GUICtrlRead( $Combo_Preset ))
	IniWrite( @ScriptDir & '\Settings.ini' , 'H264' , 'Tuning' , GUICtrlRead( $Combo_Tuning ))
	IniWrite( @ScriptDir & '\Settings.ini' , 'H264' , 'Quality', GUICtrlRead( $Combo_Quality))

	IniWrite( @ScriptDir & '\Settings.ini' , 'Deinterlace' , 'Value' , $MyINIDeinterlace )
	IniWrite( @ScriptDir & '\Settings.ini' , 'Encoder'		 , 'Value' , $MyINIEncoder )

	IniWrite( @ScriptDir & '\Settings.ini' , 'Preserve' , 'AC3' , $MyINIAC3 )
	IniWrite( @ScriptDir & '\Settings.ini' , 'Preserve' , 'DTS' , $MyINIDTS )

	IniWrite( @ScriptDir & '\Settings.ini' , 'Settings' , 'Quality' , GUICtrlRead( $Combo_Audio ))
	IniWrite( @ScriptDir & '\Settings.ini' , 'Settings' , 'Recurse' , $MyINIRecurse )
	IniWrite( @ScriptDir & '\Settings.ini' , 'Settings' , 'Shutdown', $MyINIShutdown)

	IniWrite( @ScriptDir & '\Settings.ini' , 'Last Path' , 'Path' , GUICtrlRead( $Input_FolderPath ))
EndFunc


; #FUNCTION# ===========================================================================================
; Name:             _FileListToArrayXT
; Description:      Lists files and\or folders in specified path(s) (Similar to using Dir with the /B Switch)
;                   additional features: multi-path, multi-filter, multi-exclude-filter, path format options, recursive search
;                   Corrected on 2010/08/19: Added FileClose()
; Syntax:           _FileListToArrayXT([$sPath = @ScriptDir, [$sFilter = "*", [$iRetItemType, [$bRecursive = False, [$sExclude = "", [$iRetFormat = 1]]]]]])
; Parameter(s):     $sPath = optional: Search path(s), semicolon delimited (default: @ScriptDir)
;                            (Example: "C:\Tmp;D:\Temp")
;                   $sFilter = optional: Search filter(s), semicolon delimited . Wildcards allowed. (default: "*")
;                              (Example: "*.exe;*.txt")
;                   $iRetItemType = Include in search: 0 = Files and Folder, 1 = Files Only, 2 = Folders Only
;                   $iRetPathType = Returned element format: 0 = file/folder name only, 1 = relative path, 2 = full path
;                   $bRecursive = optional: True: recursive search including all subdirectories
;                                           False (default): search only in specified folder
;                   $sExclude = optional: Exclude filter(s), semicolon delimited. Wildcards allowed.
;                               (Example: "Unins*" will remove all files/folders that begin with "Unins")
;                   $iRetFormat =  optional: return format
;                                  0 = one-dimensional array, 0-based
;                                  1 = one-dimensional array, 1-based (default)
;                                  2 = String ( "|" delimited)
; Requirement(s):   AutoIt Version 3.3.1.1 or newer
; Return Value(s):  on success: 1-based or 0-based array or string (dependent on $iRetFormat)
;                   If no path is found, @error and @extended are set to 1, returns empty string
;                   If no filter is found, @error and @extended are set to 2, returns empty string
;                   If $iRetFormat is invalid, @error and @extended are set to 3, returns empty string
;                   If no data is found, @error and @extended are set to 4, returns empty string
; Author(s):        Half the AutoIt Community
; ====================================================================================================
Func _FileListToArrayXT($sPath = @ScriptDir, $sFilter = "*", $iRetItemType = 0, $iRetPathType = 0, $bRecursive = False, $sExclude = "", $iRetFormat = 1)
	Local $hSearchFile, $sFile, $sFileList, $sWorkPath, $sRetPath, $iRootPathLen, $iPCount, $iFCount, $fDirFlag

	;[Check And Prepare Parameters]
	;---------------
	If $sPath = -1 OR $sPath = Default Then $sPath = @ScriptDir
	; Strip Leading/Trailing Spaces And Semi-Colons, All Adjacent Semi-Colons, And Spaces Surrounding Semi-Colons
	$sPath = StringRegExpReplace(StringRegExpReplace($sPath, "(\s*;\s*)+", ";"), "\A;|;\z", "")
	; Check That At Least One Path Is Set
	If $sPath = "" Then Return SetError(1, 1, "")
	;-----
	If $sFilter = -1 OR $sFilter = Default Then $sFilter = "*"
	; Prepare Filter
	; Strip Leading/Trailing Spaces And Semi-Colons, All Adjacent Semi-Colons, And Spaces Surrounding Semi-Colons
	$sFilter = StringRegExpReplace(StringRegExpReplace($sFilter, "(\s*;\s*)+", ";"), "\A;|;\z", "")
	; Check For Invalid Chars Or That At Least One Filter Is Set
	If StringRegExp($sFilter, "[\\/><:\|]|(?s)\A\s*\z") Then Return SetError(2, 2, "")
	If $bRecursive Then
		;Convert $sFilter for Regular Expression
		$sFilter = StringRegExpReplace($sFilter, '([\Q\.+[^]$(){}=!\E])', '\\$1')
		$sFilter = StringReplace($sFilter, "?", ".")
		$sFilter = StringReplace($sFilter, "*", ".*?")
		$sFilter = "(?i)\A(" & StringReplace($sFilter, ";", "$|") & "$)"	; Case-Insensitive, Convert ';' To '|', Match From First Char, Terminate Strings
		;$sFilter = "(?i)\A" & StringReplace($sFilter, ";", "|") & "\z"
	EndIf
	;-----
	If $iRetItemType <> "1" AND $iRetItemType <> "2" Then $iRetItemType = "0"
	;-----
	If $iRetPathType <> "1" AND $iRetPathType <> "2" Then $iRetPathType = "0"
	;-----
	$bRecursive = ($bRecursive = "1")
	;-----
	If $sExclude = -1 OR $sExclude = Default Then $sExclude = ""
	If $sExclude Then
	  ; Prepare $sExclude
	  ; Strip Leading/Trailing Spaces And Semi-Colons, All Adjacent Semi-Colons, And Spaces Surrounding Semi-Colons
	  $sExclude = StringRegExpReplace(StringRegExpReplace($sExclude, "(\s*;\s*)+", ";"), "\A;|;\z", "")
	  ; Convert $sExclude for Regular Expression
	  $sExclude = StringRegExpReplace($sExclude, '([\Q\.+[^]$(){}=!\E])', '\\$1')
	  $sExclude = StringReplace($sExclude, "?", ".")
	  $sExclude = StringReplace($sExclude, "*", ".*?")
	  $sExclude = "(?i)\A(" & StringReplace($sExclude, ";", "$|") & "$)"	; Case-Insensitive, Convert ';' To '|', Match From First Char, Terminate Strings
	  ;$sExclude = "(?i)\A" & StringReplace($sExclude, ";", "|") & "\z"
	EndIf
	;-----
	; If $iRetFormat <> "0" And $iRetFormat <> "2" Then $iRetFormat = "1"
	If NOT ($iRetItemType = 0 OR $iRetItemType = 1 OR $iRetItemType = 2) Then Return SetError(3, 3, "")
	;---------------
	;[/Check And Prepare Parameters]

	;---------------

	Local $aPath = StringSplit($sPath, ';', 1)		; Paths Array
	Local $aFilter = StringSplit($sFilter, ';', 1)	; Filters Array

	;---------------

	; Different Handling For Recursion (Strategy: Unfiltered Search For All Items And Filter Unwanted)
	If $bRecursive Then
		; Different Handling Dependent On $Sexclude Parameter Is Set Or Not
		If $sExclude Then
			; Path Loop
			For $iPCount = 1 To $aPath[0]
				; Ensure Exact One Trailing Slash
				$sPath = StringRegExpReplace($aPath[$iPCount], "[\\/]+\z", "") & "\"
				If NOT FileExists($sPath) Then ContinueLoop
				$iRootPathLen = StringLen($sPath) - 1

				Local $aPathStack[1024] = [1, $sPath]

				While $aPathStack[0] > 0
					$sWorkPath = $aPathStack[$aPathStack[0]]
					$aPathStack[0] -= 1
					;-----
					$hSearchFile = FileFindFirstFile($sWorkPath & '*')
					If @Error Then
						FileClose($hSearchFile)
						ContinueLoop
					EndIf
					;-----
					Switch $iRetPathType
						; Full Path
						Case 2
							$sRetPath = $sWorkPath
						; Relative Path
						Case 1
							$sRetPath = StringTrimLeft($sWorkPath, $iRootPathLen + 1)
					EndSwitch
					;-----
					Switch $iRetItemType
						; Files Only
						Case 1
							While True
								$sFile = FileFindNextFile($hSearchFile)
								If @Error Then
									FileClose($hSearchFile)
									ExitLoop
								EndIf
								$fDirFlag = @Extended
								If $fDirFlag Then
									$aPathStack[0] += 1
									If UBound($aPathStack) <= $aPathStack[0] Then ReDim $aPathStack[UBound($aPathStack) * 2]
									$aPathStack[$aPathStack[0]] = $sWorkPath & $sFile & "\"
									ContinueLoop
								EndIf
								If StringRegExp($sFile, $sExclude) Then ContinueLoop
								If StringRegExp($sFile, $sFilter) Then
									$sFileList &= $sRetPath & $sFile & "|"
								EndIf
							WEnd
						; FoldeRs Only
						Case 2
							While True
								$sFile = FileFindNextFile($hSearchFile)
								If @Error Then
									FileClose($hSearchFile)
									ExitLoop
								EndIf
								$fDirFlag = @Extended
								If StringRegExp($sFile, $sExclude) Then ContinueLoop
								If $fDirFlag Then
									$aPathStack[0] += 1
									If UBound($aPathStack) <= $aPathStack[0] Then ReDim $aPathStack[UBound($aPathStack) * 2]
									$aPathStack[$aPathStack[0]] = $sWorkPath & $sFile & "\"
									If StringRegExp($sFile, $sFilter) Then
										$sFileList &= $sRetPath & $sFile & "|"
									EndIf
								EndIf
							WEnd
						; Files And Folders
						Case Else
							While True
								$sFile = FileFindNextFile($hSearchFile)
								If @Error Then
									FileClose($hSearchFile)
									ExitLoop
								EndIf
								$fDirFlag = @Extended
								If StringRegExp($sFile, $sExclude) Then ContinueLoop
								If $fDirFlag Then
									$aPathStack[0] += 1
									If UBound($aPathStack) <= $aPathStack[0] Then ReDim $aPathStack[UBound($aPathStack) * 2]
									$aPathStack[$aPathStack[0]] = $sWorkPath & $sFile & "\"
								EndIf
								If StringRegExp($sFile, $sFilter) Then
									$sFileList &= $sRetPath & $sFile & "|"
								EndIf
							WEnd
					EndSwitch
					;-----
				WEnd
				FileClose($hSearchFile)
			; $iPCount - Next Path
			Next
		; If Not $sExclude
		Else
			; Path Loop
			For $iPCount = 1 To $aPath[0]
				; Ensure Exact One Trailing Slash
				$sPath = StringRegExpReplace($aPath[$iPCount], "[\\/]+\z", "") & "\"
				If NOT FileExists($sPath) Then ContinueLoop
				$iRootPathLen = StringLen($sPath) - 1

				Local $aPathStack[1024] = [1, $sPath]

				While $aPathStack[0] > 0
					$sWorkPath = $aPathStack[$aPathStack[0]]
					$aPathStack[0] -= 1
					;-----
					$hSearchFile = FileFindFirstFile($sWorkPath & '*')
					If @Error Then
						FileClose($hSearchFile)
						ContinueLoop
					EndIf
					;-----
					Switch $iRetPathType
						; Full Path
						Case 2
							$sRetPath = $sWorkPath
						; Relative Path
						Case 1
							$sRetPath = StringTrimLeft($sWorkPath, $iRootPathLen + 1)
					EndSwitch
					;-----
					Switch $iRetItemType
						; Files Only
						Case 1
							While True
								$sFile = FileFindNextFile($hSearchFile)
								If @Error Then
									FileClose($hSearchFile)
									ExitLoop
								EndIf
								If @Extended Then
									$aPathStack[0] += 1
									If UBound($aPathStack) <= $aPathStack[0] Then ReDim $aPathStack[UBound($aPathStack) * 2]
									$aPathStack[$aPathStack[0]] = $sWorkPath & $sFile & "\"
									ContinueLoop
								EndIf
								If StringRegExp($sFile, $sFilter) Then
									$sFileList &= $sRetPath & $sFile & "|"
								EndIf
							WEnd
						; Folders Only
						Case 2
							While True
								$sFile = FileFindNextFile($hSearchFile)
								If @Error Then
									FileClose($hSearchFile)
									ExitLoop
								EndIf
								If @Extended Then
									$aPathStack[0] += 1
									If UBound($aPathStack) <= $aPathStack[0] Then ReDim $aPathStack[UBound($aPathStack) * 2]
									$aPathStack[$aPathStack[0]] = $sWorkPath & $sFile & "\"
									If StringRegExp($sFile, $sFilter) Then
										$sFileList &= $sRetPath & $sFile & "|"
									EndIf
								EndIf
							WEnd
						; Files And Folders
						Case Else
							While True
								$sFile = FileFindNextFile($hSearchFile)
								If @Error Then
									FileClose($hSearchFile)
									ExitLoop
								EndIf
								If @Extended Then
									$aPathStack[0] += 1
									If UBound($aPathStack) <= $aPathStack[0] Then ReDim $aPathStack[UBound($aPathStack) * 2]
									$aPathStack[$aPathStack[0]] = $sWorkPath & $sFile & "\"
								EndIf
								If StringRegExp($sFile, $sFilter) Then
									$sFileList &= $sRetPath & $sFile & "|"
								EndIf
							WEnd
					EndSwitch
					;-----
				WEnd
				FileClose($hSearchFile)
			; $iPCount - Next Path
			Next
		; If $sExclude
		EndIf
	; If Not $bRecursive (Strategy: Filtered Search For Items)
	Else
		; Different Handling Dependent On $Sexclude Parameter Is Set Or Not
		If $sExclude Then
			; Path Loop
			For $iPCount = 1 To $aPath[0]
				; Ensure Exact One Trailing Slash
				$sPath = StringRegExpReplace($aPath[$iPCount], "[\\/]+\z", "") & "\"
				If NOT FileExists($sPath) Then ContinueLoop
				;-----
				Switch $iRetPathType
					; Full Path
					Case 2
						$sRetPath = $sPath
					; Relative Path
					Case 1
						$sRetPath = ""
				EndSwitch

				; Filter Loop
				For $iFCount = 1 To $aFilter[0]
					;-----
					$hSearchFile = FileFindFirstFile($sPath & $aFilter[$iFCount])
					If @Error Then
						FileClose($hSearchFile)
						ContinueLoop
					EndIf
					;-----
					Switch $iRetItemType
						; Files Only
						Case 1
							While True
								$sFile = FileFindNextFile($hSearchFile)
								If @Error Then
									FileClose($hSearchFile)
									ExitLoop
								EndIf
								; Bypass Folder
								If @Extended Then ContinueLoop
								; Check For Exclude Files
								If StringRegExp($sFile, $sExclude) Then ContinueLoop
								$sFileList &= $sRetPath & $sFile & "|"
							WEnd
						; Folders Only
						Case 2
							While True
								$sFile = FileFindNextFile($hSearchFile)
								If @Error Then
									FileClose($hSearchFile)
									ExitLoop
								EndIf
								; Bypass File
								If @Extended Then
									; Check For Exclude Folder
									If StringRegExp($sFile, $sExclude) Then ContinueLoop
									$sFileList &= $sRetPath & $sFile & "|"
								EndIf
							WEnd
						; Files And Folders
						Case Else
							While True
								$sFile = FileFindNextFile($hSearchFile)
								If @Error Then
									FileClose($hSearchFile)
									ExitLoop
								EndIf
								; Check For Exclude Files/Folder
								If StringRegExp($sFile, $sExclude) Then ContinueLoop
								$sFileList &= $sRetPath & $sFile & "|"
							WEnd
					EndSwitch
					FileClose($hSearchFile)
				; $iFCount - Next Filter
				Next
			; $iPCount - Next Path
			Next
		; If Not $sExclude
		Else
			; Path Loop
			For $iPCount = 1 To $aPath[0]
				; Ensure Exact One Trailing Slash
				$sPath = StringRegExpReplace($aPath[$iPCount], "[\\/]+\z", "") & "\"
				If NOT FileExists($sPath) Then ContinueLoop
				;-----
				Switch $iRetPathType
					; Full Path
					Case 2
						$sRetPath = $sPath
					; Relative Path
					Case 1
						$sRetPath = ""
				EndSwitch

				; Filter Loop
				For $iFCount = 1 To $aFilter[0]
					;-----
					$hSearchFile = FileFindFirstFile($sPath & $aFilter[$iFCount])
					If @Error Then
						FileClose($hSearchFile)
						ContinueLoop
					EndIf
					;-----
					Switch $iRetItemType
						; Files Only
						Case 1
							While True
								$sFile = FileFindNextFile($hSearchFile)
								If @Error Then
									FileClose($hSearchFile)
									ExitLoop
								EndIf
								; Bypass Folder
								If @Extended Then ContinueLoop
								$sFileList &= $sRetPath & $sFile & "|"
							WEnd
						; Folders Only
						Case 2
							While True
								$sFile = FileFindNextFile($hSearchFile)
								If @Error Then
									FileClose($hSearchFile)
									ExitLoop
								EndIf
								; Bypass File
								If @Extended Then
									$sFileList &= $sRetPath & $sFile & "|"
								EndIf
							WEnd
						; Files And Folders
						Case Else
							While True
								$sFile = FileFindNextFile($hSearchFile)
								If @Error Then
									FileClose($hSearchFile)
									ExitLoop
								EndIf
								$sFileList &= $sRetPath & $sFile & "|"
							WEnd
					EndSwitch
					FileClose($hSearchFile)
				;$iFCount - Next Filter
				Next
			; $iPCount - Next Path
			Next
		; If $sExclude
		EndIf
	; If $bRecursive
	EndIf

	;---------------

	; Set According Return Value
	If $sFileList Then
		Switch $iRetFormat
			; Return A Delimited String
			Case 2
				Return StringTrimRight($sFileList, 1)
			; Return A 0-Based Array
			Case 0
				Return StringSplit(StringTrimRight($sFileList, 1), "|", 2)
			; Return A 1-Based Array
			Case Else
				Return StringSplit(StringTrimRight($sFileList, 1), "|", 1)
		EndSwitch
	Else
		Return SetError(4, 4, "")
	EndIf
EndFunc   ;==>_FileListToArrayX